package scenic.path;

import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Ellipse2D;
import java.awt.geom.NoninvertibleTransformException;
import java.awt.geom.PathIterator;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;

import scenic.Util;

public class AWTShapePath implements Path {
	public Shape shape;
	private static double points[] = new double[10000];

	public AWTShapePath(Shape shape) {
		this.shape = shape;
	}
	
	private void walk(PathWalker walker, double points[], int l, boolean closed) {
		walker.beginSubPath(closed);
		for(int i = 0; i < l; i += 2) {
			walker.lineTo(points[i], points[i + 1]);
		}
		walker.endSubPath();
	}
	
	public Path createGenericPath() {
		PathBuilder pathBuilder = new PathBuilder();
		PathIterator itr = shape.getPathIterator(null);
		double[] point = new double[6];
		
		while(!itr.isDone()) {
			int type = itr.currentSegment(point);
			
			itr.next();
			if(type == PathIterator.SEG_MOVETO) {
				pathBuilder.moveTo(point[0], point[1]);
			} else if(type == PathIterator.SEG_LINETO) {
				pathBuilder.lineTo(point[0], point[1]);				
			} else if(type == PathIterator.SEG_QUADTO) {
				Point2D.Double p1 = new Point2D.Double(point[0], point[1]);
				Point2D.Double p2 = new Point2D.Double(point[2], point[3]);
				pathBuilder.curveTo(p1, p2);
			} else if(type == PathIterator.SEG_CUBICTO) {
				Point2D.Double p1 = new Point2D.Double(point[0], point[1]);
				Point2D.Double p2 = new Point2D.Double(point[2], point[3]);
				Point2D.Double p3 = new Point2D.Double(point[4], point[5]);
				pathBuilder.curveTo(p1, p2, p3);
			} else if(type == PathIterator.SEG_CLOSE) {
				pathBuilder.close();
			}
		}
		
		return pathBuilder.createPath();
	}
	
	public void walk(PathWalker walker, AffineTransform errorMatrix,
			double error) {
		PathIterator itr = shape.getPathIterator(errorMatrix, error);
		double[] point = new double[6];
		int i = 0;
		AffineTransform inv;
		double m00, m01, m10, m11, dx, dy;
		
		try {
			 inv = errorMatrix.createInverse();
		} catch (NoninvertibleTransformException e) {
			return;
		}
		
		m00 = inv.getScaleX();
		m01 = inv.getShearX();
		m10 = inv.getShearY();
		m11 = inv.getScaleY();
		dx = inv.getTranslateX();
		dy = inv.getTranslateY();
		
		while(!itr.isDone()) {
			int type = itr.currentSegment(point);
			
			itr.next();
			if(type == PathIterator.SEG_MOVETO) {
				if(i > 0) {
					walk(walker, points, i, false);
					i = 0;
				}
				points[i++] = m00 * point[0] + m01 * point[1] + dx;
				points[i++] = m10 * point[0] + m11 * point[1] + dy;
			} else if(type == PathIterator.SEG_LINETO) {
				points[i++] = m00 * point[0] + m01 * point[1] + dx;
				points[i++] = m10 * point[0] + m11 * point[1] + dy;
			} else if(type == PathIterator.SEG_CLOSE) {
				if(i > 0) {
					walk(walker, points, i, true);
					i = 0;
				}
			}
		}
		if(i > 0) {
			walk(walker, points, i, false);
			i = 0;
		}
	}
	
	public Rectangle getBounds(AffineTransform transform) {
		return Util.transform(transform, shape.getBounds());
	}
	
	public boolean isConvex() {
		return shape instanceof Ellipse2D ||
			shape instanceof Rectangle2D;
	}
}
